#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "snmpapi.h"
#include "utils.h"

extern BOOLEAN Config_Parse(PCONFIG_DATA pConfigData, char *pszConfigFile);
extern void yyerror(const char *format, ...);
extern int yylex();

BOOLEAN
ResetConfig(PCONFIG_DATA pcd)
{
  memset(pcd, 0, sizeof(CONFIG_DATA));
  return TRUE;
}

BOOLEAN
ResetDevice(PDEVICE pdev)
{
  memset(pdev, 0, sizeof(DEVICE));
  return TRUE;
}

BOOLEAN
ResetInterface(PINTERFACE pif)
{
  memset(pif, 0, sizeof(INTERFACE));
  return TRUE;
}

void
CleanupInterface(PINTERFACE pif)
{
  free(pif->pstrDescr);
  free(pif->pstrTitle);
  free(pif->pstrComment);
  free(pif->pstrURL);
  ResetInterface(pif);
}

void
CleanupDevice(PDEVICE pdev)
{
  free(pdev->pstrAddress);
  free(pdev->pstrCommunity);
  while(!DLL_IsEmpty(&pdev->dllInterfaces))
  {
    PINTERFACE pif=DLL_RemoveHead(&pdev->dllInterfaces);

    CleanupInterface(pif);
    free(pif);
  }
  ResetDevice(pdev);
}

void
CleanupConfig(PCONFIG_DATA pcd)
{
  free(pcd->pstrMailEventsFrom);
  free(pcd->pstrMailEventsTo);
  free(pcd->pstrConfigFile);
  free(pcd->pstrWorkingDirectory);
  while(!DLL_IsEmpty(&pcd->dllDevices))
  {
    PDEVICE pdev=DLL_RemoveHead(&pcd->dllDevices);

    CleanupDevice(pdev);
    free(pdev);
  }
  ResetConfig(pcd);
}

PINTERFACE
MatchInterfaceIdOnDevice(PDEVICE pdev, int nId)
{
  PDLLELEM peif=DLL_GetHeadElem(&pdev->dllInterfaces);

  while(peif)
  {
    PINTERFACE pif=DLL_GetNextElem(&peif);

    if(pif->nId==nId)
    {
      return pif;
    }
  }
  return NULL;
}

PINTERFACE
MatchInterfaceIdOnAllDevices(PDLLIST pdllDevices, int nId)
{
  PDLLELEM pedev=DLL_GetHeadElem(pdllDevices);

  while(pedev)
  {
    PDEVICE pdev=DLL_GetNextElem(&pedev);
    PINTERFACE pif=MatchInterfaceIdOnDevice(pdev, nId);

    if(pif)
    {
      return pif;
    }
  }
  return NULL;
}

PDEVICE
MatchDeviceId(PCONFIG_DATA pcd, int nId)
{
  PDLLELEM pedev=DLL_GetHeadElem(&pcd->dllDevices);

  while(pedev)
  {
    PDEVICE pdev=DLL_GetNextElem(&pedev);

    if(pdev->nId==nId)
    {
      return pdev;
    }
  }
  return NULL;
}

BOOLEAN
AddDevice(PCONFIG_DATA pcd, PDEVICE pdev)
{
  char *pszErrMsg=NULL;
  PDEVICE pdevNew=NULL;

  if(MatchDeviceId(pcd, pdev->nId))
  {
    pszErrMsg="duplicate device id specified";
    goto end;
  }

  if(!pdev->pstrAddress)
  {
    pszErrMsg="device address not specified";
    goto end;
  }

  if(!pdev->pstrCommunity)
  {
    pszErrMsg="device community not specified";
    goto end;
  }

  pdevNew=malloc(sizeof(DEVICE));
  if(!pdevNew)
  {
    pszErrMsg="memory allocation for new device failed";
    goto end;
  }

  *pdevNew=*pdev;

  if(!DLL_InsertTail(&pcd->dllDevices, pdevNew))
  {
    pszErrMsg="adding new device failed";
    goto end;
  }

end:
  if(pszErrMsg)
  {
    free(pdevNew);
    CleanupDevice(pdev);
    yyerror(pszErrMsg);
    return FALSE;
  }
  ResetDevice(pdev);
  return TRUE;
}

BOOLEAN
AddInterface(PDLLIST pdllDevices, PDEVICE pdev, PINTERFACE pif)
{
  char *pszErrMsg=NULL;
  PINTERFACE pifNew=NULL;

  if(MatchInterfaceIdOnDevice(pdev, pif->nId) ||
     MatchInterfaceIdOnAllDevices(pdllDevices, pif->nId))
  {
    pszErrMsg="duplicate interface id specified";
    goto end;
  }

  if(!pif->pstrDescr)
  {
    pszErrMsg="interface description not specified";
    goto end;
  }

  pifNew=malloc(sizeof(INTERFACE));
  if(!pifNew)
  {
    pszErrMsg="memory allocation for new interface failed";
    goto end;
  }

  *pifNew=*pif;
  pifNew->nPrevOperStatus=SNMP_IFSTATUS_UP;
  pifNew->nLastOperStatus=SNMP_IFSTATUS_UP;

  if(!DLL_InsertTail(&pdev->dllInterfaces, pifNew))
  {
    pszErrMsg="adding new interface failed";
    goto end;
  }

end:
  if(pszErrMsg)
  {
    free(pifNew);
    CleanupInterface(pif);
    yyerror(pszErrMsg);
    return FALSE;
  }
  ResetInterface(pif);
  return TRUE;
}

void
Config_Consolidate(PCONFIG_DATA pcd, PCONFIG_DATA pcdNew)
{
  PDLLELEM peDevNew;

  peDevNew=DLL_GetHeadElem(&pcdNew->dllDevices);
  while(peDevNew)
  {
    PDEVICE pdevNew;
    PDLLELEM peIfsNew;

    pdevNew=DLL_GetNextElem(&peDevNew);
    peIfsNew=DLL_GetHeadElem(&pdevNew->dllInterfaces);
    while(peIfsNew)
    {
      PINTERFACE pifNew, pif;

      pifNew=DLL_GetNextElem(&peIfsNew);
      pif=MatchInterfaceIdOnAllDevices(&pcd->dllDevices, pifNew->nId);
      if(pif)
      {
        pifNew->nPrevOperStatus=pif->nPrevOperStatus;
        pifNew->nLastOperStatus=pif->nLastOperStatus;
        pifNew->timeLastPolled=pif->timeLastPolled;
        pifNew->timeWhenWentDown=pif->timeWhenWentDown;
        pifNew->timeElapsedToReminder=pif->timeElapsedToReminder;
      }
    }
  }
  CleanupConfig(pcd);
  *pcd=*pcdNew;
}

int
Config_Read(PCONFIG_DATA pConfigData, char szConfigFile[])
{
  if(!Config_Parse(pConfigData, szConfigFile))
  {
    return -1;
  }
  return 0;
}

